Macintosh System7, GRAME's MidiShare™ and (optional) Apple's MidiManager
André Ch. Schnoor, Hamburg (Germany)
czesanne@mail.hh.provi.de
czesanne@proaudio.de
This source is public domain. You may distribute, use and modify this material as you like.
You need Objectworks\Smalltalk™ R4.1 from ParcPlace Systems as well as a copy of the GRAME MidiShare™ 1.68 package (which is freely available from ftp.grame.fr). You also need a MPW Workbench to compile the C-code and link it together with the Smalltalk virtual machine. I have encountered problems linking the st-80.lib using other C-Compilers because this library is full of MPW C specific stuff - may be it's possible for a real C-freak to port this code.
Please keep me informed of any future modifications and developments based on this material.
Subject
The included C source code implements system primitives for the Objectworks\Smalltalk-80™ virtual machine for interfacing the MidiShare™ real-time midi engine on the Apple Macintosh. This code was tested with MidiShare™ 1.68 and Objectworks\Smalltalk 4.1™ (ParcPlace). The interface was originally developed for the LEVIATHAN™ music composition system. You may change all the strings containing "Leviathan" in the source to any name you like.
Features
The Smalltalk primitives allow asynchronous midi in/out with comfortable sequencer-like start/stop/tempo control. Only the following event types have been included yet: NOTES, CONTROL CHANGES, PROGRAM CHANGES. This will suit for most applications that deal with music composition rather than studio integration. The interface uses comfortable sequencer-ticks and beats-per-minute values instead of milliseconds which are internally used by MidiShare™.
MidiManager Bridge
A bridge to the Apple MidiManager has been included. This allows to control instruments which are connected internally (e.g. SampleCell II™ Soundcards) rather than beeing plugged into the external midi interface. When the Smalltalk midi interface is "opened", an icon representing the Smalltalk midi in/out appears in the midi patchbay control panel. The user can then make the desired connections to other instruments. You may refer to the two MidiManager ports by using the constants
MidiShareInterface midiManagerPort0
MidiShareInterface midiManagerPort1
as the port parameter when sending events.
Compilation
The C-primitives can be compiled with the included makefile using the MPW. The procedure of adding user primitives to the Smalltalk virtual machine is explained in detail in the Objectworks manual. The makefile automatically links the compiled code together with the virtual machine (select "Build..." from the MPW menu and enter "st80-midi"). The file "MidiShare.h" needs to be placed in the same folder together with the complete stuff from ParcPlace (userprim.h, st80.lib etc).
It is very important to adjust the correct memory sizes (command-I) for the new virtual machine executable. Otherwise the new Smalltalk VM would not launch.
Smalltalk Part
The included Smalltalk class "MidiShareInterface" handles the communication with MidiShare™. Simply create a new instance of this class and use it for communicating with MidiShare. The following methods are implemented:
open
Simply opens the connection to MidiShare™. If Apple MidiManager is
installed, an icon representing the Smalltalk midi interface will
appear in the MidiPatchbay control panel.
offset: o tempo: t resolution: resolution delay: ms
Defines the timing constants to be used while playing/recording with
MidiShare™. The required units are:
offset = sequencer ticks,
resolution = sequencer ticks p. 4/4 (e.g. 1920),
tempo = BPM (e.g. 120),
delay = milliseconds.
The offset will be subtracted from all event timestamps. This allows
instant playback of later events without modifying the events.
primSend: clock port: port chan: chan type: type data1: d1 data2: d2 data3: d3
Sends a midi event. The timestamp is given in sequencer ticks instead
of milliseconds. The C-Primitive will convert these values to milliseconds.
This is much faster and convenient than doing all this in Smalltalk.
clock = sequencer tick-position of the event
port = 0..8=MidiShare ports, 9,10=MidiManager ports
chan = midi channel
type = MidiShare event type (see MidiShare doc.)
d1..d3 = MidiShare event bytes:
NOTE d1=pitch, d2=velocity, d3=duration
CONTROLLER d1=controller, d2=value
PROGRAM d1=program number
This method was named "prim..." because you may encapsulate it within
a higher method that is able to deal with your custom event-objects.
recordEnable, recordDisable
Turn on/off the recording of events between start/stop.
start
Start playback (and recording, if enabled)
stop
Stop playback (and recording).
received
Answer a collection of all events that have been received since the
last start. Since the interface receives raw byte-data, you have to
implement the method receiveConvert: aByteArray (private) to
convert the raw data into you custom event-objects.
close
Closes the interface.
status
Answer a verbose string showing the current status of the interface.